﻿#include "vm/value.h"
#include "mem.h"
#include "vm/vm.h"

#include "snprintf.h" 

#include <stdio.h>
#include <string.h>

Value bool_val(VmBoolean boolean)
{
    Value v;
    v.type = VAL_BOOL;
    v.as.boolean = boolean;
    return v;
}

Value nil_val()
{
    Value v;
    v.type = VAL_NIL;
    v.as.number = 0;
    return v;
}

Value number_val(VmNumber number)
{
    Value v;
    v.type = VAL_NUMBER;
    v.as.number = number;
    return v;
}

//steven+8种基本类型 //TokenType t 保留
Value integer2_val(VmInteger integer)
{
    Value v;
    v.type = VAL_INT;
    v.as.integer = integer;
    return v;
}
Value uinteger2_val(VmUInteger uinteger)
{
    Value v;
    v.type = VAL_UINT;
    v.as.uinteger = uinteger;
    return v;
}


Value object_val(VmObject* object)
{
    Value v;
    v.type = VAL_OBJECT;
    v.as.object = object;
    return v;
}

void value_array_init(ValueArray* array)
{
    array->count = 0;
    array->capacity = 0;
    array->values = NULL;
}

void value_array_write(ValueArray* array, Value value)
{
    int oldCapacity = array->capacity;
    if (array->capacity < array->count + 1) {
        array->capacity = GROW_CAPACITY(oldCapacity);
        array->values = GROW_ARRAY(array->values, Value, oldCapacity, array->capacity);
    }

    array->values[array->count] = value;
    array->count++;
}

void value_array_free(ValueArray* array)
{
    FREE_ARRAY(Value, array->values, array->capacity);
    value_array_init(array);
}

int object_equal(Value a, Value b)
{
    VmString *s1 = NULL, *s2 = NULL;
    if (AS_OBJECT(a)->type != AS_OBJECT(b)->type) {
        return 0;
    }

    switch (AS_OBJECT(a)->type) {
    case OBJECT_STRING:
        s1 = AS_STRING(a);
        s2 = AS_STRING(b);
        return s1 == s2;
    }

    return 0;
}



//==运算要值大小和累I型那个都相同,相似相等,用一个单独的函数来做
int values_equal(Value a, Value b)
{
    if (a.type != b.type) {
        return 0;
    }

    switch (a.type) {
    case VAL_BOOL:
        return AS_BOOL(a) == AS_BOOL(b);
    //steven+
    case VAL_INT:
        return AS_INTEGER(a) == AS_INTEGER(b);
    case VAL_UINT:
        return AS_UINTEGER(a) == AS_UINTEGER(b);        
        
    case VAL_NUMBER:
        return AS_NUMBER(a) == AS_NUMBER(b);
    case VAL_NIL:
        return 1;
    case VAL_OBJECT:
        return object_equal(a, b);
    }

    return 0;
}

static void object_print(Value value)
{
    VmObject* object = AS_OBJECT(value);

    switch (object->type) {
    case OBJECT_STRING:
        printf("%s", AS_CSTRING(value));
        break;
    case OBJECT_FUNCTION:
        if (AS_FUNCTION(value)->name != NULL) {
            printf("<fn %s>", AS_FUNCTION(value)->name->chars);
        } else {
            printf("<script>");
        }
        break;
    case OBJECT_NATIVE:
        printf("<native fn>");
        break;
        
    //steven+不真正输出数据
    case OBJECT_ARRAY:
       printf("<array>");
        break;
    //map可以考虑输出
    case OBJECT_MAP:
       printf("<map>");
        break;
    }
}

void value_print(Value value)
{
    char str[1024];
    switch (value.type) 
    {
    case VAL_NUMBER:
        printf("%g", AS_NUMBER(value));
        break;
    //steven+输出整形,无符号整形  
    case VAL_INT:
        my_snprintf(str,1024,"%lld", AS_INTEGER(value));
        printf("%s",str);
        break; 
    case VAL_UINT:
        my_snprintf(str,1024,"%llu", AS_UINTEGER(value));
        printf("%s",str);
        break;          
        
    case VAL_BOOL:
        printf(AS_BOOL(value) ? "true" : "false");
        break;
    case VAL_NIL:
        printf("nil");
        break;
    case VAL_OBJECT:
        object_print(value);
        break;
    }
}

static void vmstring_free(VmString* string)
{
    FREE_ARRAY(char, string->chars, string->length + 1);
    FREE(VmString, string);
}
//steven+
static void vmarray_free(VmArray* array)
{
    FREE_ARRAY(char, array->data, array->length );
    FREE(VmArray, array);
}

static void object_free(VmObject* object)
{
    VmString* string = NULL;
    VmArray* array = NULL;
    VmFunction* function = NULL;
    switch (object->type) 
    {
    case OBJECT_STRING:
        string = (VmString*)object;
        vmstring_free(string);
        break;
    case OBJECT_FUNCTION:
        function = (VmFunction*)object;
        chunk_free(&function->chunk);
        //vmstring_free(function->name);
        FREE(VmFunction, function);
        break;
    case OBJECT_NATIVE:
        FREE(VmNative, object);
        break;
    //
    case OBJECT_ARRAY:
        array = (VmArray*)object;
        vmarray_free(array);
        break;
        
    }
}

void objects_free()
{
    VmObject *object = vm.objects, *next = NULL;
    while (object != NULL) {
        next = object->next;
        object_free(object);
        object = next;
    }
}
